      <h1 class="entry-title entry-title-single" itemprop="headline">T-SQL 编程之结果集循环处理</h1>

    <div class="entry-content entry-content-single entry-content-aside" itemprop="text">
      <h4>1.<span class='wp_keywordlink_affiliate'><a href="http://www.sapjx.com/tag/cursor" title="查看游标中的全部文章" target="_blank">游标</a></span>循环</h4>
<p>在关系数据库中，循环遍历数据的方式，可以通过<span class='wp_keywordlink_affiliate'><a href="http://www.sapjx.com/tag/cursor" title="查看游标中的全部文章" target="_blank">游标</a></span>来实现。</p>
<p>通常查询数据时都是以集合的方式进行的，然而<span class='wp_keywordlink_affiliate'><a href="http://www.sapjx.com/tag/cursor" title="查看游标中的全部文章" target="_blank">游标</a></span>打破了这一规则，可以进行逐行的查询；</p>
<p><span id="more-600"></span><br />
&nbsp;</p>
<p>在<span class='wp_keywordlink_affiliate'><a href="http://www.sapjx.com/tag/sql" title="查看T-SQL中的全部文章" target="_blank">T-SQL</a></span>中，游标的生命周期由5部分组成，也就是说，要使用游标，必须执行以下这5个步骤：</p>
<p>1).定义游标</p>
<p>2).打开游标</p>
<p>3).使用游标</p>
<p>4).关闭游标</p>
<p>5).释放游标</p>
<p>&nbsp;</p>
<p>简单示例：</p>
<pre class="brush: sql;">

-- 检查临时表

IF NOT object_id(‘TempDB.. #temp’) IS NULL

Begin

DROP TABLE TempDB..#Temp_table

End


-- 创建临时表

Create Table TempDB..#Temp_table (a int, b int)



-- 1. 定义游标

Declare cur1 CURSOR FOR

-- 游标查询数据集合

Insert into TempDB..#Temp_table

       Select 1, 2


Declare @i int,


-- 2.打开游标

OPEN cur


-- 3.使用游标

FETCH cur  INTO @i

While @@fetch_status = 0

Begin

    Print @i


    -- 下一条记录

    Fetch cur into @i

End


-- 4. 关闭游标

Close cur

IF NOT object_id(‘TempDB.. #temp’) IS NULL

Gegin

DROP TABLE TempDB..#Temp_table

End


-- 5. 释放游标

Deallocate cur

</pre>
<p>&nbsp;</p>
<h4>2.游标嵌套循环</h4>
<p>对于游标的嵌套循环操作，在 &#8220;使用游标&#8221; 的周期时，再次执行一次游标循环：</p>
<pre class="brush: sql;">

Create Table #temp(a int,b int)

Insert Into #temp

       Select 1,2

Insert Into #temp

       Select 3,4


Select * From #temp


Declare @i int,  @j int

Declare cur1 Cursor For

     Select a From #temp

Open cur1

Fetch cur1 into @i

WHILE @@fetch_status =0

Begin

       Select 'cur1:', @i

       -- 内部循环

       Declare cur2 Cursor For

               Select b From #temp

       Open cur2

       Fetch cur2 into @j

       WHILE @@fetch_Status =0

       Begin

             Select 'cur2:',@j

             Fetch cur2 into @j

       End

       Close cur2

       Deallocate cur2

Fetch cur1 into @i

End


Close cur1

Drop Table #temp

Deallocate cur1

</pre>
<p>&nbsp;</p>
<h4>3. 游标的优缺点</h4>
<p>优点：逐行查询，优化数据处理，方便开发人员</p>
<p>缺点：性能上，消耗更多的内存，减少可用的并发，占用带宽，锁定资源，代码量大，可读性差；</p>
<p>不难看出，使用游标的缺点多于其优点，但其存在必定有其作用，SQL Server中的系统多处使用游标检索、处理数据。</p>
<p>在开发中，可以将游标作为一种备用，当我们穷尽了 While循环,子查询，临时表，表变量，自建<span class='wp_keywordlink'><a href="http://www.sapjx.com/tag/function" title="函数" target="_blank">函数</a></span>或其他方式扔来无法实现某些查询的时候，使用游标实现</p>
<p>&nbsp;</p>
<h4>4. 避免使用游标的处理方法</h4>
<p>可以通过While循环、变量、临时表等方式，来避免使用游标。</p>
<p>这里有两种方法可以避免使用游标，如若还不能满足需求，就只能回头使用游标了。</p>
<p>&nbsp;</p>
<p>第一种方法（常用方法）：</p>
<pre class="brush: sql;">

-- 定义一个表变量（必须包含自增长的ID主键）

Declare @tempTable table(ID int identity(1,1), unitID int, unitState int, partID bigint)

Insert into @tempTable

       Select distinct u.id, u.UnitStateID, u.PartID

       From ffUnit u

       Join ffUnitDetail ud On u.id =  ud.unitID

       Where ud.InmostPackageID = @packageID 



--  定义累加变量

Declare @i int

Declare @j int

Set @i = 0

Select @j = MAX(ID) From @tempTable


WHILE @i < @j

Begin

      Set @i = @i + 1

      Set @UnitID = null

      Set @CurrUnitStateID = null

      Set @PartID = null

      Select @UnitID = unitID, @CurrUnitStateID = unitState, @PartID = partID

             From @tempTable

             Where ID = @i

      Drop Table @ tempTable Where ID = @i

End

Drop Table @tempTable

</pre>
<p>&nbsp;</p>
<p>第二种方法（使用ROW_NUMBER<span class='wp_keywordlink'><a href="http://www.sapjx.com/tag/function" title="函数" target="_blank">函数</a></span>）：</p>
<pre class="brush: sql;">

Declare @row int

Declare @number int;

Declare @Temp_table Table ( [name] nvarchar(200))

Select ROW_NUMBER() OVER (ORDER BY [Name] ) AS number,[name] INTO #nn1 
 
       From dbo.code

Select @number = MAX(number) From #nn1

Set @row = 1

WHILE (@row <= @number)

Begin

     Inert Into @Temp_table

           Select [name] From #nn1

                  Where number = @row

     Set @row = @row + 1

END

DROP TABLE #nn1

</pre>
<p>&nbsp;</p>
<p>&nbsp;</p>
<p>参考文章：</p>
<p><a href="http://www.2cto.com/database/201304/200084.html" target="_blank">http://www.2cto.com/database/201304/200084.html</a></p>
<p>&nbsp;</p>